6.6 Typumwandlung von Objektvariablen  
6.6.1 Die implizite Typumwandlung von Objektreferenzen  
Kommen wir noch einmal auf das Beispiel der Klassenhierarchie der Luftfahrzeuge zurück. Die Klasse Luftfahrzeug beschreibt Eigenschaften und Operationen, die allen Luftfahrzeugen, unabhängig vom Typ, eigen sind. Die Klassen Zeppelin, Starrflügler und Hubschrauber beerben als abgeleitete Klassen die Basisklasse. Am Beispiel des Zeppelins lautet der Code:
| Class Luftfahrzeug
|
| ' Anweisungen
|
| End Class
|
| Class Zeppelin
|
| Inherits Luftfahrzeug
|
| ' Anweisungen
|
| End Class
|
Zwischen diesen beiden Klassen liegt eine Ist-eine-Beziehung vor: Ein Objekt vom Typ Zeppelin ist gleichzeitig auch ein Objekt vom Typ Luftfahrzeug. Diese Zuordnung hat Konsequenzen, denn aufgrund dieser Beziehung kann man die Referenz auf ein Subklassenobjekt einer Referenz auf ein Basisklassenobjekt zuweisen:
| Dim zpln As New Zeppelin
|
| Dim lfzg As Luftfahrzeug = zpln
|
|
Stehen zwei Klassen miteinander in einer Vererbungsbeziehung, kann eine Referenz vom Typ der abgeleiteten Klasse der Referenz vom Typ einer der Basisklassen mit
<Basisklassenreferenz> = <Subklassenreferenz>
zugewiesen werden. Dabei erfolgt eine implizite Konvertierung.
|
Die beiden Variablen zpln und lfzg referenzieren denselben Speicherbereich – jedoch mit einer kleinen Einschränkung: Die Laufzeitumgebung betrachtet lfzg nur als Objekt vom Typ Luftfahrzeug und nicht als Zeppelin. Damit hat die Objektreferenz lfzg auch keinen Zugriff auf die Operationen, durch die sich ein Objekt vom Typ Zeppelin auszeichnet.
Die Tatsache, dass ein Objekt vom Typ einer abgeleiteten Klasse auch gleichzeitig ein Objekt vom Typ seiner Basisklasse ist, kann man sich bei der Typfestlegung eines Parameters zunutze machen:
| Public Sub TestProc(ByVal lfzg As Luftfahrzeug)
|
| ' Anweisungen
|
| End Sub
|
Die Methode TestProc erwartet vom Aufrufer die Referenz auf ein Luftfahrzeug. Ob es sich dabei um einen Zeppelin, einen Hubschrauber oder einen sonstigen Typ handelt, spielt keine Rolle. Ausschlaggebend ist nur, dass der Typ der übergebenen Referenz von Luftfahrzeug abgeleitet ist. Zeppelin erfüllt diese Bedingung. Daher kann die Methode TestProc folgendermaßen aufgerufen werden:
| Dim zpln As New Zeppelin
|
| IrgendEinObjekt.TestProc(zpln)
|
Wie die Entwicklungsumgebung auf den umgekehrten Fall reagiert, nämlich die Zuweisung einer Basisklassenreferenz an eine Referenz vom Typ der abgeleiteten Klasse, hängt von der Einstellung des Schalters Option Strict ab. Ist er auf On eingestellt, führt der folgende Code zu einer Fehlermeldung:
| Dim lfzg As New Luftfahrzeug
|
| ' die folgende Anweisung ist falsch
|
| Dim zpln As Zeppelin = lfzg
|
Der Grund des Fehlers ist einfach zu verstehen: Das Objekt einer abgeleiteten Klasse kann mehr zustandsbeschreibende Daten (also Felder) aufweisen als das Objekt seiner Basisklasse. Die Methoden der Subklasse müssen aber auf die typspezifischen Daten zugreifen können. Genau hier liegt der springende Punkt, wenn der Versuch unternommen wird, mit
| <Subklassenreferenz> = <Basisklassenreferenz>
|
den Compiler hinters Licht zu führen.
Das Verhalten lässt sich auch anschaulich erklären. Alle Felder eines bestimmten Typs werden über eine Schnittstelle offen gelegt – ob es sich dabei um eine öffentliche Deklaration eines Feldes oder um das Veröffentlichen eines privaten Feldes über eine Eigenschaftsmethode handelt, spielt keine Rolle. Bei einer Zuweisung nach dem Muster
| <Basisklassenreferenz> = <Subklassenreferenz>
|
müssen alle Entitäten der links vom Zuweisungsoperator angegebenen Referenz einen konkreten Bezug zu einem Mitglied der rechts vom Zuweisungsoperator stehenden Referenz haben. Betrachten Sie dazu die folgende Abbildung, die diesen Sachverhalt anschaulich darstellt. Dass dabei das Feld Gasvolumen einer Zeppelin-Referenz keinen Abnehmer in der Luftfahrzeug-Referenz findet, spielt keine Rolle.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 6.5 Die Zuweisung einer Subklassenreferenz an eine Basisklassenreferenz
Würde die Referenz vom Typ der Basisklasse einer Referenz vom Typ der abgeleiteten Klasse zugewiesen, hätte das beim Zugriff auf das objektspezifische Feld Gasvolumen des Zeppelins fatale Folgen, denn das Feld wäre nicht initialisiert. Der VB-Compiler versagt deshalb die Kompilierung.
6.6.2 Die explizite Typumwandlung von Objektreferenzen  
In Kapitel 3 haben Sie bereits gelernt, einen elementaren Datentyp in einen anderen umzuwandeln. Diese Umwandlung wird als Konvertierung oder Casting bezeichnet. Eine Konvertierung wird implizit – also ohne Interaktion seitens des Entwicklers – ausgeführt, wenn die Operation eine Aufweitung des Datentyps zur Folge hat. Das ist beispielsweise der Fall, wenn der Inhalt eines Integer einem Long zugewiesen wird:
| Dim intVar As Integer = 4711
|
| Dim lngVar As Long = intVar
|
Bei der umgekehrten Zuweisung verhält sich die Entwicklungsumgebung gemäß der Einstellung von Option Strict. Haben Sie die Standardeinstellung Off beibehalten, können Sie auch eine einengende Operation angeben, ohne explizit konvertieren zu müssen. Steht der Schalter jedoch auf On, muss die Operation mit
intVar = CInt(lngVar)
erzwungen werden.
Von einer operativen Aufweitung spricht man auch, wenn man eine Subklassenreferenz einer Basisklassenreferenz zuweist, also in der Vererbungshierarchie dem Beziehungspfeil nach oben folgt. So wie ein Long allgemeiner ist als ein Integer, weil er den gesamten Wertebereich des Integer abdeckt, gilt auch eine Basisklasse allgemeiner als eine Subklasse, denn die Subklasse enthält ohne jeden Zweifel alle Mitglieder der Basisklasse.
Nehmen wir zum Beispiel unsere beiden Klassen Circle und GraphicCircle. Dabei sei myCircle die Referenz auf ein Circle-Objekt und myGraphCircle die Referenz auf ein GraphicCircle-Objekt.
| Dim myCircle As New Circle
|
| Dim myGraphCircle As GraphicCircle
|
Die Zuweisung
konvertiert implizit, weil sich die Typen beider Referenzen in einer Vererbungsbeziehung befinden und das Versprechen der Referenz myGraphCircle, allen Mitgliedern von myCircle etwas übergeben zu können, erfüllt werden kann.
Um bei der Schalterstellung Option Strict On die umgekehrte Zuweisung zu erzwingen, kommt die Konvertierungsfunktion CType zum Einsatz:
| myGraphCircle = CType(myCircle, GraphicCircle)
|
Damit wird sie dem ersten Parameter von CType für die explizit zu konvertierende Referenz übergeben, dem zweiten der Typ, in den konvertiert werden soll.
Selbstverständlich meldet sich der VB-Compiler mit einem Fehlerhinweis, wenn keine Möglichkeit besteht, eine erfolgreiche Typumwandlung vorzunehmen, beispielsweise:
| ' fehlerhafte Typumwandlung
|
| Dim obj As ClassA = CType(myCircle, ClassA)
|
Der Typ der Referenz myCircle befindet sich in keiner Vererbungsbeziehung zu ClassA, daher ist der Versuch der Typumwandlung zum Scheitern verurteilt. Eine Vererbungsbeziehung ist also eine unausweichliche Voraussetzung der expliziten Konvertierung.
6.6.3 Zusammenfassung  
|
Die von einer Basisklasse geerbte Methode kann in der abgeleiteten Klasse neu implementiert werden. Die Neuimplementierung verdeckt dann die geerbte Methode. Voraussetzung ist eine identische Signatur gemäß den Regeln der Methodenüberladung. Die Methode, die eine geerbte Methode verdeckt, muss zusätzlich mit dem Modifizierer Shadows signiert werden. |
|
Das komplette Ausblenden eines geerbten Mitglieds in einer abgeleiteten Klasse ist nicht möglich. |
|
Um einen abgeleiteten Typ zu spezialisieren, kann die von einer Basisklasse geerbte Methode in der abgeleiteten Klasse überladen werden. Die überladene Methode darf sich nur in der Parameterliste von der geerbten, die weiterhin in der Subklasse sichtbar ist, unterscheiden. |
|
Eine Ist-eine-Beziehung beschreibt die Beziehung zweier Klassen in einer Vererbungslinie. Eine Hat-eine-Beziehung (Aggregation) liegt dann vor, wenn innerhalb einer Klasse ein Feld ein Objekt referenziert. Der Benutzer hat auf das Objekt entweder direkten Zugriff über eine Eigenschaft oder über die Aufrufumleitung einer zwischengeschalteten typspezifischen Methode. |
|
Ist ein Objekt an die Existenz eines anderen gebunden, bietet es sich an, das abhängige Objekt in der umgebenden Klasse zu definieren. Man spricht dann auch von einer inneren Klasse. |
|
Wird einer Variablen vom Typ einer Basisklasse die Referenz auf ein Objekt einer Subklasse zugewiesen, erfolgt eine implizite Typkonvertierung. Die Zuweisung einer Basisklassenreferenz an eine Variable vom Typ der Subklasse hängt von der Stellung des Schalters Option Strict ab. Ist er Off, wird eine solche Zuweisung eine implizite Konvertierung zur Folge haben. Ist er On, ist die Zuweisung nur möglich, wenn mit der Funktion CType konvertiert wird. Voraussetzung dabei ist, dass sich beide Klassen auf einer Vererbungslinie befinden. |
|